package com.wmx.wmxredis.properties;

import com.wmx.wmxredis.resultAPI.ResultData;
import org.springframework.beans.factory.config.YamlMapFactoryBean;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.*;

/**
 * 1、ConfigurationProperties 为 java bean 注入属性值
 * 2、Spring 框架提供两个便捷的类用于加载 YAML 文 档，
 * YamlPropertiesFactoryBean 会将 YAML 加载为 Properties;
 * YamlMapFactoryBean 会将YAML 加载为 Map;
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2020/9/25 9:18
 */
@RestController
@SuppressWarnings("Duplicates")
public class PropertiesController {

    /**
     * 从容器中获取实例
     */
    @Resource
    private UserProperties userProperties;

    @Resource
    private PersonProperties personProperties;

    @Resource
    private StaffProperties staffProperties;

    @Resource
    private AppEnvironment appEnvironment;

    /**
     * ConfigurationProperties + Component  取值演示
     * <p>
     * http://localhost:8080/properties/getDefaultUser
     *
     * @return
     */
    @GetMapping("properties/getDefaultUser")
    public UserProperties getDefaultUser() {
        return userProperties;
    }

    /**
     * ConfigurationProperties + Bean 取值演示
     * <p>
     * http://localhost:8080/properties/getDefaultPerson
     *
     * @return
     */
    @GetMapping("properties/getDefaultPerson")
    public PersonProperties getDefaultPerson() {
        return personProperties;
    }

    /**
     * ConfigurationProperties + EnableConfigurationProperties 取值演示
     * <p>
     * http://localhost:8080/properties/getDefaultStaff
     *
     * @return
     */
    @GetMapping("properties/getDefaultStaff")
    public StaffProperties getDefaultStaff() {
        return staffProperties;
    }

    /**
     * Spring 提供了 YamlPropertiesFactoryBean 可以读取任意 yml 文件内容
     * http://localhost:8080/properties/yamlProperties1
     *
     * @return
     */
    @GetMapping("properties/yamlProperties1")
    public Map<String, String> yamlProperties1() {
        YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
        // 类路径下的任意 yml 文件.
        yamlPropertiesFactoryBean.setResources(new ClassPathResource("application.yml"));
        // 转Properties对象，方便取值
        Properties properties = yamlPropertiesFactoryBean.getObject();
        /**
         * Properties 根据属性名获取属性值
         * String getProperty(String key)：用指定的键在此属性列表中搜索属性。
         * * 如果在此属性列表中未找到该键，则接着递归检查默认属性列表及其默认值，如果还未找到属性，则此方法返回 null。
         * String getProperty(String key, String defaultValue)
         * * 在原来的基础上，如果当前属性列表与默认属性列表中都没有值时，则返回 defaultValue 作为默认值
         */
        // 遍历全部配置——方式1
        // 因为 Properties extends Hashtable，所以也可以使用遍历 Map 方式进行遍历
        Map<String, String> paramMap = new LinkedHashMap<>();
        Enumeration<?> propertyNames = properties.propertyNames();
        while (propertyNames.hasMoreElements()) {
            // key 全部是字符串类型.
            String propertyName = (String) propertyNames.nextElement();
            String propertiesValue = properties.getProperty(propertyName);
            paramMap.put(propertyName, propertiesValue);
        }
        return paramMap;
    }

    /**
     * Spring 提供了 YamlPropertiesFactoryBean 可以读取任意 yml 文件内容
     * http://localhost:8080/properties/yamlProperties2
     *
     * @return
     */
    @GetMapping("properties/yamlProperties2")
    public Map<String, Object> yamlProperties2() {
        YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
        // 类路径下的任意 yml 文件.
        yamlPropertiesFactoryBean.setResources(new ClassPathResource("application.yml"));
        // 转Properties对象，方便取值
        Properties properties = yamlPropertiesFactoryBean.getObject();
        // 遍历全部配置——方式2
        // 因为 Properties extends Hashtable，所以也可以使用遍历 Map 方式进行遍历
        // 返回的 Properties 中的键值对不保证和原内容的顺序一致，所以干脆使用 TreeMap 根据 key 的自然顺序进行排序.
        // yml 文件中没有设置的属性值的，这里的value是一个空字符串
        Map<String, Object> paramMap = new TreeMap<>();
        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
            paramMap.put(entry.getKey().toString(), entry.getValue());
        }
        return paramMap;
    }

    /**
     * Spring 提供了 YamlMapFactoryBean 会将 YAML 加载为 Map。
     * http://localhost:8080/properties/yamlMapFactoryBean1
     *
     * @return
     */
    @GetMapping("properties/yamlMapFactoryBean1")
    public Map<String, Object> yamlMapFactoryBean1() {
        YamlMapFactoryBean yamlMapFactoryBean = new YamlMapFactoryBean();
        // 类路径下的任意 yml 文件.
        yamlMapFactoryBean.setResources(new ClassPathResource("application.yml"));
        Map<String, Object> yamlMap = yamlMapFactoryBean.getObject();
        return yamlMap;
    }

    /**
     * 获取系统当前生效的全局 application.yml 的全部配置，而不用在指定具体的文件路径。
     * 通常服务部署运行时，读取都是jar包外部的配置，所以与位置无关，读取的都是服务当前使用的配置。
     * <p>
     * http://localhost:8080/properties/environmentAware1
     * <p>
     * 这种方式和 YamlPropertiesFactoryBean 一样，返回的 key-value 会对 yml 中的复杂类型进行特殊处理，比如数组和map。
     * 比如数组返回：user.colorList[1]，括号是索引位置。
     * 比如map返回：user.cityMap.mapK2，mapK2是map中的key名称。
     *
     * @return
     */
    @GetMapping("properties/environmentAware1")
    public ResultData environmentAware1() {
        // 获取当前系统全部 yml 配置
        Map<String, String> allYmlConfig = appEnvironment.getAllYmlConfig();
        return ResultData.success(allYmlConfig);
    }

    /**
     * 读取yml中指定 key 的配置。
     * <p>
     * http://localhost:8080/properties/environmentAware2?ymlKey=person.birthday
     * http://localhost:8080/properties/environmentAware2?ymlKey=spring.redis.jedis.pool.max-active
     * http://localhost:8080/properties/environmentAware2?ymlKey=person.colorList[2]
     * http://localhost:8080/properties/environmentAware2?ymlKey=staff.cityMap.mapK2
     *
     * @param ymlKey
     * @return
     */
    @GetMapping("properties/environmentAware2")
    public ResultData environmentAware2(String ymlKey) {
        // 获取当前系统全部 yml 配置
        String ymlByKey = appEnvironment.getYmlByKey(ymlKey);
        return ResultData.success(ymlByKey);
    }

}
